/*-
 * Copyright (c) 2009 Jonathan Anderson
 * All rights reserved.
 *
 * WARNING: THIS IS EXPERIMENTAL SECURITY SOFTWARE THAT MUST NOT BE RELIED
 * ON IN PRODUCTION SYSTEMS.  IT WILL BREAK YOUR SOFTWARE IN NEW AND
 * UNEXPECTED WAYS.
 * 
 * This software was developed at the University of Cambridge Computer
 * Laboratory with support from a grant from Google, Inc. 
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef _LIBUSERANGEL_H_
#define	_LIBUSERANGEL_H_

#include <sys/cdefs.h>
#include <sys/stat.h>

#include <dirent.h>
#include <stdio.h>

__BEGIN_DECLS


/* Powerbox-related types */

/** Powerbox UI types */
enum ua_powerbox_ui_t { UA_DUMMY, UA_QT, UA_KDE /* TODO: GNOME, NCURSES, etc. */ };

/** Powerbox operations */
enum ua_powerbox_op_t { UA_OPEN_FILE, UA_SAVE_FILE, UA_SELECT_DIR };

/** Options which control a powerbox */
struct ua_powerbox_options
{
	enum ua_powerbox_ui_t	ui;            /* UI type */
	enum ua_powerbox_op_t	operation;     /* operation to perform */
	char*			window_title;  /* set by user_angel, not sandbox */
	int			parent_window; /* X11 window to attach to (or 0) */
	const char*		start_path;    /* path to start in (or NULL) */
	unsigned int		pathlen;       /* length of start path */
	int			start_fd;      /* FD to start in (or -1) */
	int			mult;          /* allow multiple selection */
	const char*		filter;        /* filter expression (or NULL) */
	int			filterlen;     /* length of filter expression */
	int			flags;         /* open() flags, e.g. O_RDONLY */
	cap_rights_t		rights;        /* capabilities, e.g. CAP_SEEK */
	int			umask;         /* umask, for open() with O_CREAT */
};



/* High-level API */

/** Version of the User Angel protocol */
const char* ua_protocol_version(void);

/** Set the client name (to appear in powerboxes, etc.) */
int ua_set_client_name(const char *client_name);

/** Find the user angel (at $HOME/.user-angel or the like) */
int ua_find(void);

/** Set the user angel */
void ua_set(int fd);

/** Ping the user angel to make sure the connection works */
int ua_ping(void);

/** Cache a file descriptor */
int ua_cache_fd(int fd, const char *name, char **token, int long_lasting);

/** Retrieve a cached file descriptor */
int ua_retrieve_fd(const char *token);

/**
 * Open a powerbox.
 *
 * @param   options     powerbox options
 * @param   fds         an array for file descriptors (size len)
 * @param   names       an array for file names (size len)
 * @param   len         the length of the above arrays (modified by this call)
 *
 * @return  0 on success
 */
int ua_powerbox(struct ua_powerbox_options *options,
                int fds[], char *names[], int *len);

/** Check access rights via the User Angel */
int ua_access(const char *access, int mode);

/** Check file status via the User Angel */
int ua_stat(const char *path, struct stat *s);

/** Open a file via the User Angel */
int ua_open(const char *path, int flags, ...);

/** Open a file via the User Angel, specifying rights the capability should have */
int ua_ropen(const char *path, int flags, cap_rights_t rights, int umask);

/** Open a file stream via the User Angel */
FILE* ua_fopen(const char *path, const char *mode);

/** Open a directory via the User Angel */
DIR* ua_opendir(const char *filename);


/* Low-level API */

/** Requests that clients can make */
enum ua_request_t
{
	UA_NO_OP = 0,		/* do nothing (useful for debugging) */
	UA_CACHE_FD,            /* cache a file descriptor */
	UA_RETRIEVE_FD,         /* retrieve a cached file descriptor */
	UA_CHECK_ACCESS,        /* access() substitute */
	UA_STAT,                /* stat() substitute */
	UA_OPEN_PATH,		/* open() substitute */
	UA_OPEN_DIR,            /* opendir() substitute */
	UA_LOAD_LIBRARY,	/* load a shared library */
	UA_POWERBOX		/* ask the user for file descriptor(s) */
};


/** Represents information "on the wire" between the user angel and the sandbox */
struct ua_datum
{
	uint32_t type;
	#define	TYPE_PRIMITIVE_MASK	0x000000ff
	#define	INTEGER			0x00000001
	#define	FLOAT			0x00000002
	#define	STRING			0x00000004
	#define	CAPBOX_OPTIONS		0x00000008
	#define ERROR			0x00000080

	#define TYPE_MODIFIER_MASK	0x0000ff00
	#define	LONG			0x00000100
	#define	SHORT			0x00000200
	#define	UNSIGNED		0x00000400

	uint32_t length;

	/* immediately followed by raw data; */
};


/** Send a datum, with [optional] accompanying file descriptors */
int ua_send(int sock, struct ua_datum *d, int32_t fds[], int32_t fdlen);

/** Receive a datum, with [optional] accompanying file descriptors */
struct ua_datum* ua_recv(int sock, int32_t fds[], uint32_t *fdlen);



/* Unmarshalling functions; calling programs should free the result */
struct ua_datum* ua_marshall_int(int32_t value);
struct ua_datum* ua_marshall_long(int64_t value);
struct ua_datum* ua_marshall_string(const char *value, unsigned int len);
struct ua_datum* ua_marshall_error(int errnum, const char *msg, unsigned int msglen);
struct ua_datum* ua_marshall_powerbox(const struct ua_powerbox_options *options);


/* Unmarshalling functions; return the number of bytes unmarshalled (or -1) */
int ua_unmarshall_int(const struct ua_datum *d, int32_t *value);
int ua_unmarshall_long(const struct ua_datum *d, int64_t *value);
int ua_unmarshall_bytes(const struct ua_datum *d, char *value, unsigned int *len);
int ua_unmarshall_string(const struct ua_datum *d, char *value, unsigned int *len);
int ua_unmarshall_error(const struct ua_datum *d, int *errnum, char *msg, int *msglen);
int ua_unmarshall_powerbox(const struct ua_datum *d, struct ua_powerbox_options *options);

__END_DECLS

#endif /* !_LIBUSERANGEL_H_ */

